﻿using System;
using System.Runtime.InteropServices;
using System.Text;

namespace InfiniTec.Security.Certificates
{
    internal static class SafeNativeMethods
    {
        [DllImport("msvcrt.dll")]
        public static extern int system(
            string syscommand);

        //--------  CryptoAPI  CSP and key functions ----------------------
        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool CryptAcquireContext(
            out IntPtr hProv,
            [MarshalAs(UnmanagedType.LPWStr)] string pszContainer,
            string pszProvider,
            CryptographicProvider dwProvType,
            KeyContainerOptions dwFlags);

        [DllImport("crypt32.dll", SetLastError = true)]
        public static extern bool CertSetCertificateContextProperty(
            IntPtr pCertContext,
            uint dwPropId,
            uint dwFlags,
            CRYPT_KEY_PROV_INFO pvData);

        [DllImport("crypt32.dll", SetLastError = true)]
        public static extern bool CertAddCertificateContextToStore(
            IntPtr hCertStore,
            IntPtr hCertificate,
            uint flags,
            out IntPtr ppStoreContext);

        [DllImport("advapi32.dll")]
        public static extern bool CryptReleaseContext(
            IntPtr hProv,
            uint dwFlags);

        [DllImport("advapi32.dll")]
        public static extern bool CryptGetUserKey(
            IntPtr hProv,
            KeySpecification dwKeySpec,
            out IntPtr hKey);

        [DllImport("advapi32.dll")]
        public static extern bool CryptGenKey(
            IntPtr hProv,
            KeySpecification dwKeySpec,
            uint dwFlags,
            out IntPtr hKey);


        [DllImport("advapi32.dll", SetLastError = true)]
        public static extern bool CryptExportKey(
            IntPtr hKey,
            IntPtr hExpKey,
            uint dwBlobType,
            uint dwFlags,
            [In, Out] byte[] pbData,
            ref uint dwDataLen);


        [DllImport("advapi32.dll")]
        public static extern bool CryptDestroyKey(
            IntPtr hKey);


        [DllImport("advapi32.dll")]
        public static extern bool CryptGetKeyParam(
            IntPtr hKey,
            uint dwParam,
            ref uint prop,
            ref uint dwDataLen,
            uint dwFlags);


        [DllImport("advapi32.dll", SetLastError = true)]
        public static extern bool CryptGetProvParam(
            IntPtr hProv,
            uint dwParam,
            [In, Out] byte[] pbData,
            ref uint dwDataLen,
            uint dwFlags);

        [DllImport("advapi32.dll", SetLastError = true)]
        public static extern bool CryptGetProvParam(
            IntPtr hProv,
            uint dwParam,
            [MarshalAs(UnmanagedType.LPStr)] StringBuilder pbData,
            ref uint dwDataLen,
            uint dwFlags);


        [DllImport("crypt32.dll")]
        public static extern bool CryptEncodeObject(
            uint CertEncodingType,
            uint lpszStructType,
            byte[] pbData,
            [In, Out] byte[] pbEncoded,
            ref uint cbEncoded);

        [DllImport("crypt32.dll")]
        public static extern bool CryptEncodeObject(
            uint CertEncodingType,
            uint lpszStructType,
            ref CERT_PUBLIC_KEY_INFO pvStructInfo,
            [In, Out] byte[] pbEncoded,
            ref uint cbEncoded);


        //---------- CryptoAPI certificate functions --------------------

        [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)] //overloaded
        public static extern IntPtr CertOpenStore(
            IntPtr storeProvider,
            uint dwMsgAndCertEncodingType,
            IntPtr hCryptProv,
            uint dwFlags,
            String cchNameString);


        [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr CertOpenSystemStore(
            IntPtr hCryptProv,
            string storename);

        [DllImport("crypt32.dll", SetLastError = true)]
        public static extern bool CertCloseStore(
            IntPtr hCertStore,
            uint dwFlags);

        [DllImport("crypt32.dll", SetLastError = true)]
        public static extern bool CertFreeCertificateContext(
            IntPtr hCertStore);

        [DllImport("crypt32.dll", SetLastError = true)]
        public static extern IntPtr CertEnumCertificatesInStore(
            IntPtr hCertStore,
            IntPtr pPrevCertContext);

        [DllImport("crypt32.dll", SetLastError = true)]
        public static extern bool CertGetCertificateContextProperty(
            IntPtr pCertContext, uint dwPropId, IntPtr pvData, ref uint pcbData);


        [DllImport("crypt32.dll", SetLastError = true)]
        public static extern IntPtr CertFindCertificateInStore(
            IntPtr pCertStore,
            uint dwCertEncodingType,
            uint dwFindFlags,
            uint dwFindType,
            ref HASH_BLOB phash,
            IntPtr pPrevCertCntxt);

        [DllImport("crypt32.dll", SetLastError = true)]
        public static extern IntPtr CertFindCertificateInStore(
            IntPtr hCertStore,
            uint dwCertEncodingType,
            uint dwFindFlags,
            uint dwFindType,
            IntPtr pvFindPara,
            IntPtr pPrevCertCntxt);


        [DllImport("cryptui.dll", SetLastError = true)]
        public static extern bool CryptUIDlgViewCertificate(
            ref PCCRYPTUI_VIEWCERTIFICATE_STRUCT pCertViewInfo,
            ref bool pfPropertiesChanged);


        [DllImport("crypt32.dll", SetLastError = true)]
        public static extern bool CryptExportPublicKeyInfoEx(
            IntPtr hProv,
            uint dwKeySpec,
            uint dwCertEncodingType,
            String pxzPublicKeyObjId,
            uint dwFlags,
            IntPtr pvAuxInfo,
            IntPtr pInfo,
            ref uint pcbInfo);


        [DllImport("crypt32.dll", SetLastError = true)]
        public static extern int CertGetPublicKeyLength(
            uint dwCertEncodingType,
            IntPtr pPublicKeyInfo);


        [DllImport("crypt32.dll", SetLastError = true)]
        public static extern IntPtr CertCreateSelfSignCertificate(
            IntPtr hProv,
            ref CERT_NAME_BLOB pSubjectIssuerBlob,
            uint dwFlagsm,
            CRYPT_KEY_PROV_INFO pKeyProvInfo,
            IntPtr pSignatureAlgorithm,
            SysTime pStartTime,
            SysTime pEndTime,
            ref CertExtensions other);


        [DllImport("crypt32.dll", SetLastError = true)]
        public static extern IntPtr CertCreateSelfSignCertificate(
            IntPtr hProv,
            ref CERT_NAME_BLOB pSubjectIssuerBlob,
            uint dwFlagsm,
            IntPtr pinfo,
            IntPtr pSignatureAlgorithm,
            SysTime pStartTime,
            SysTime pEndTime,
            IntPtr other);


        [DllImport("crypt32.dll", SetLastError = true)]
        public static extern bool CertStrToName(
            X509Encoding dwCertEncodingType,
            String pszX500,
            X509Encoding dwStrType,
            IntPtr pvReserved,
            [In, Out] byte[] pbEncoded,
            ref uint pcbEncoded,
            IntPtr other);


        [DllImport("crypt32.dll", SetLastError = true)]
        public static extern bool CryptExportPKCS8Ex(
            ref CRYPT_PKCS8_EXPORT_PARAMS psExportParams,
            uint dwFlags,
            IntPtr pvAuxInfo,
            [In, Out] byte[] pbPrivateKeyBlob,
            ref uint pcbPrivateKeyBlob);


        [DllImport("crypt32.dll", SetLastError = true)]
        public static extern bool CryptExportPKCS8(
            IntPtr hCryptProv,
            uint dwKeySpec,
            String pszPrivateKeyObjId,
            uint dwFlags,
            IntPtr pvAuxInfo,
            [In, Out] byte[] pbPrivateKeyBlob,
            ref uint pcbPrivateKeyBlob);
    }


    //--------  Win32 structs prototypes ---------------


    [StructLayout(LayoutKind.Sequential)]
    internal struct PUBKEYBLOBHEADERS
    {
        public byte bType; //BLOBHEADER
        public byte bVersion; //BLOBHEADER
        public short reserved; //BLOBHEADER
        public uint aiKeyAlg; //BLOBHEADER
        public uint magic; //RSAPUBKEY
        public uint bitlen; //RSAPUBKEY
        public uint pubexp; //RSAPUBKEY
    }


    [StructLayout(LayoutKind.Sequential)]
    internal class CRYPT_KEY_PROV_INFO
    {
        [MarshalAs(UnmanagedType.LPWStr)] public String pwszContainerName;
        [MarshalAs(UnmanagedType.LPWStr)] public String pwszProvName;
        public CryptographicProvider dwProvType;
        public CspOptions dwFlags;
        public uint cProvParam;
        public IntPtr rgProvParam;
        public KeySpecification dwKeySpec;
    }


    [StructLayout(LayoutKind.Sequential)]
    internal struct PCCRYPTUI_VIEWCERTIFICATE_STRUCT
    {
        public uint dwSize; //required
        public IntPtr hwndParent;
        public uint dwFlags;
        public String szTitle;
        public IntPtr pCertContext; //required
        public IntPtr rgszPurposes;
        private uint cPurposes;
        private IntPtr hWVTStateData;
        private bool fpCryptProviderDataTrustedUsage;
        private uint idxSigner;
        private uint idxCert;
        private bool fCounterSigner;
        private uint idxCounterSigner;
        private uint cStores;
        private IntPtr rghStores;
        private uint cPropSheetPages;
        private IntPtr rgPropSheetPages;
        public uint nStartPage; //required
    }


    [StructLayout(LayoutKind.Sequential)]
    internal struct HASH_BLOB
    {
        public int cbData;
        public IntPtr pbData;
    }


    [StructLayout(LayoutKind.Sequential)]
    internal struct CERT_NAME_BLOB
    {
        public int cbData;
        public IntPtr pbData;
    }


    [StructLayout(LayoutKind.Sequential)]
    internal struct CERT_PUBLIC_KEY_INFO
    {
        public String SubjPKIAlgpszObjId;
        public int SubjPKIAlgParameterscbData;
        public IntPtr SubjPKIAlgParameterspbData;
        public int PublicKeycbData;
        public IntPtr PublicKeypbData;
        public int PublicKeycUnusedBits;
    }


    [StructLayout(LayoutKind.Sequential)]
    internal struct CERT_CONTEXT
    {
        public uint dwCertEncodingType;
        public IntPtr pbCertEncoded;
        public int cbCertEncoded;
        public IntPtr pCertInfo;
        public IntPtr hCertStore;
    }


    [StructLayout(LayoutKind.Sequential)]
    internal struct CRYPT_PKCS8_EXPORT_PARAMS
    {
        public IntPtr hCryptProv;
        public uint dwKeySpec;
        public String pszPrivateKeyObjId;
        public IntPtr pEncryptPrivateKeyFunc;
        public IntPtr pVoidEncryptFunc;
    }


    [StructLayout(LayoutKind.Sequential)]
    internal class SysTime
    {
        public ushort wYear;
        public ushort wMonth;
        public ushort wDayOfWeek;
        public ushort wDay;
        public ushort wHour;
        public ushort wMinute;
        public ushort wSecond;
        public ushort wMilliseconds;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct CertExtensions
    {
        public uint cExtension;
        public IntPtr rgExtension;
    }
}